package com.simafei.flow.web.controller;


import com.simafei.flow.core.FlowConstants;
import com.simafei.flow.core.common.FieldScope;
import com.simafei.flow.web.common.CommonResult;
import com.simafei.flow.web.domain.graph.FlowGraph;
import com.simafei.flow.web.domain.req.*;
import com.simafei.flow.web.domain.resp.FlowResp;
import com.simafei.flow.web.domain.resp.FlowResultResp;
import com.simafei.flow.web.domain.resp.PageResult;
import com.simafei.flow.web.domain.resp.VariableResp;
import com.simafei.flow.web.service.IFlowService;
import com.simafei.flow.web.util.DownloadUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


/**
 * 流程 http api 入口
 *
 * @author generator
 * @since 2023-05-05
 */
@Tag(name = "流程编排(版本)")
@RestController
@RequestMapping("/flow")
@Slf4j
@RequiredArgsConstructor
public class FlowController {

    private final IFlowService flowService;

    @Operation(summary = "新增流程")
    @PostMapping("/add")
    public CommonResult<FlowResp> add(@Validated @RequestBody FlowReq req) {
        return CommonResult.success(flowService.add(req));
    }

    @Operation(summary = "新增流程编排")
    @PostMapping("/addGraph")
    public CommonResult<FlowResp> addGraph(@Validated @RequestBody FlowGraph graph) {
        return CommonResult.success(flowService.addGraph(graph));
    }

    @Operation(summary = "暂存流程设计")
    @PostMapping("/save")
    public CommonResult<Void> save(@Validated @RequestBody GraphSaveReq graph) {
        flowService.update(graph.getFlowId(), graph.getGraph());
        return CommonResult.success();
    }

    @Operation(summary = "流程导出")
    @GetMapping("/export")
    public ResponseEntity<ByteArrayResource> export(@RequestParam Long flowId) {
        FlowResp flowResp = flowService.get(flowId);
        return DownloadUtils.toResponseEntity(flowResp.getFlowName() + ".json", flowResp.getGraph());
    }

    @Operation(summary = "流程导入")
    @PostMapping("/import")
    public CommonResult<String> importFlow(@RequestParam Long flowId, @RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            return CommonResult.error("文件为空");
        }
        try {
            String fileContent = new String(file.getBytes(), StandardCharsets.UTF_8);
            flowService.update(flowId, fileContent);
        } catch (Exception e) {
            log.error("导入流程失败", e);
            return CommonResult.error("导入流程失败");
        }
        return CommonResult.success(String.valueOf(flowId));
    }

    @Operation(summary = "新增流程版本")
    @PostMapping("/newVersion")
    public CommonResult<FlowResp> newVersion(@RequestParam Long flowId) {
        return CommonResult.success(flowService.newVersion(flowId));
    }

    @Operation(summary = "删除流程")
    @PostMapping("/delete")
    public CommonResult<Void> delete(@RequestParam Long flowId) {
        boolean delete = flowService.delete(flowId);
        return delete ? CommonResult.success() : CommonResult.error();
    }

    @Operation(summary = "根据Id查询流程")
    @GetMapping("/get")
    public CommonResult<FlowResp> get(@RequestParam Long flowId) {
        return CommonResult.success(flowService.get(flowId));
    }

    @Operation(summary = "查询流程列表")
    @PostMapping("/page")
    public CommonResult<PageResult<FlowResp>> page(@Validated @RequestBody PageParam param) {
        return CommonResult.success(flowService.queryPage(param));
    }

    @Operation(summary = "查询分类下流程列表")
    @PostMapping("/listByCategory")
    public CommonResult<List<FlowResp>> listByCategory(@RequestParam Long categoryId) {
        return CommonResult.success(flowService.listByCategory(categoryId));
    }

    @Operation(summary = "查询分组下所有决策")
    @PostMapping("/listByGroup")
    public CommonResult<List<FlowResp>> listByGroup(@RequestParam Long groupId) {
        return CommonResult.success(flowService.listByGroup(groupId));
    }

    @Operation(summary = "测试流程编排")
    @PostMapping("/test")
    public SseEmitter test(@RequestBody FlowExecReq req) {
        return flowService.test(req);
    }

    @Operation(summary = "恢复流程编排执行")
    @PostMapping("/resume")
    public SseEmitter resume(@RequestBody ResumeReq req) {
        return flowService.resume(req);
    }

    @Operation(summary = "执行流程")
    @PostMapping("/{flowId}/execute")
    public CommonResult<FlowResultResp> execute(@Parameter(description = "流程Id") @PathVariable Long flowId,
                                                @RequestBody Map<String, Object> param) {
        return CommonResult.success(flowService.execute(flowId, param));
    }

    @Operation(summary = "异步执行流程")
    @PostMapping("/{flowId}/executeAsync")
    public CommonResult<String> executeAsync(@Parameter(description = "流程Id") @PathVariable Long flowId,
                                           @RequestBody Map<String, Object> param) {
        return CommonResult.success(flowService.executeAsync(flowId, param));
    }

    @Operation(summary = "获取流程输入参数列表", description = "前端测试流程时使用,修改为开始节点的输入参数")
    @GetMapping("/flowVars")
    @Deprecated
    public CommonResult<List<VariableResp>> getFlowVars(@RequestParam Long flowId) {
        return CommonResult.success(flowService.getFlowVars(flowId));
    }

    @Operation(summary = "获取流程输入参数列表", description = "生成API文档")
    @GetMapping("/generateDoc")
    public CommonResult<List<VariableResp>> generateDoc(@RequestParam Long flowId) {
        return CommonResult.success(flowService.getFlowVars(flowId));
    }

    @Operation(summary = "查询系统内置变量列表")
    @GetMapping("/systemVars")
    public CommonResult<List<VariableResp>> systemVars() {
        List<VariableResp> systemVars = new ArrayList<>();
        for (FlowConstants.SystemVars value : FlowConstants.SystemVars.values()) {
            VariableResp dto = getSystemVar(value);
            systemVars.add(dto);
        }
        return CommonResult.success(systemVars);
    }

    private VariableResp getSystemVar(FlowConstants.SystemVars value) {
        VariableResp dto = new VariableResp();
        dto.setVarName(value.getVarName());
        dto.setVarLabel(value.getVarLabel());
        dto.setVarType(value.getType());
        dto.setScope(FieldScope.REQUEST);
        dto.setOptions(value.getOptions());
        return dto;
    }

}
